package com.leyou.auth.service;

import com.leyou.auth.config.JwtProperties;
import com.leyou.auth.config.PasswordConfig;
import com.leyou.auth.entity.ApplicationInfo;
import com.leyou.auth.mapper.ApplicationInfoMapper;
import com.leyou.common.auth.entity.AppInfo;
import com.leyou.common.auth.entity.Payload;
import com.leyou.common.auth.entity.UserInfo;
import com.leyou.common.auth.utils.JwtUtils;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exception.LyException;
import com.leyou.common.utils.CookieUtils;
import com.leyou.user.client.UserClient;
import com.leyou.user.dto.UserDTO;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class AuthService {

    @Autowired
    private JwtProperties jwtProperties;

    @Autowired
    private UserClient userClient;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private ApplicationInfoMapper infoMapper;
    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    public void login(String username, String password, HttpServletResponse response) {
        try {
            // 根据用户名和密码查询用户
            UserDTO user = userClient.queryByUsernameAndPassword(username, password);
            // 生成jwt
            UserInfo userInfo = new UserInfo(user.getId(),user.getUsername(),"guest");
            String token = JwtUtils.generateTokenExpireInMinutes(userInfo, jwtProperties.getPrivateKey(), jwtProperties.getUser().getExpire());
            // 存入cookie
            CookieUtils.newCookieBuilder()
                    .name(jwtProperties.getUser().getCookieName())
                    .domain(jwtProperties.getUser().getCookieDomain())
                    .value(token)
                    .httpOnly(true)
                    .response(response).build();
        } catch (Exception e) {
            // 用户名或者密码错误
            log.error("用户名或者密码错误",e);
            throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD);
        }
    }
    /**
     * 查询cookie里面保存的token用户信息
     * @return
     */
    public UserInfo verifyUser(HttpServletRequest request,HttpServletResponse response) {
        try {
            String token = CookieUtils.getCookieValue(request, jwtProperties.getUser().getCookieName());
            Payload<UserInfo> payload = JwtUtils.getInfoFromToken(token, jwtProperties.getPublicKey(), UserInfo.class);

            //验证token黑名单是否存在
            Boolean bool = redisTemplate.hasKey(payload.getId());
            if(bool != null && bool){
                throw new LyException(ExceptionEnum.UNAUTHORIZED);
            }
            //====================重新刷新token===============================
            //获取过期时间
            Date expiration = payload.getExpiration();
            DateTime dateTime = new DateTime(expiration).minusMinutes(jwtProperties.getUser().getRefreshTime());
            if(dateTime.isBeforeNow()){
                //重新生成token
                token = JwtUtils.generateTokenExpireInMinutes(payload.getUserInfo(), jwtProperties.getPrivateKey(), jwtProperties.getUser().getExpire());
                CookieUtils.newCookieBuilder()
                        .name(jwtProperties.getUser().getCookieName())
                        .domain(jwtProperties.getUser().getCookieDomain())
                        .value(token)
                        .httpOnly(true)
                        .response(response).build();
            }
            return payload.getUserInfo();
        } catch (Exception e) {
            throw new LyException(ExceptionEnum.UNAUTHORIZED);
        }
    }

    /**
     * 用户退出
     * @param request
     * @param response
     * @return
     */
    public void logout(HttpServletRequest request, HttpServletResponse response) {
        String token = CookieUtils.getCookieValue(request, jwtProperties.getUser().getCookieName());
        Payload<Object> payload = null;
        try {
            payload = JwtUtils.getInfoFromToken(token, jwtProperties.getPublicKey());
        } catch (Exception e) {
            return;
        }
        // 获取token的剩余有效期
        long remainTime = payload.getExpiration().getTime() - System.currentTimeMillis();
        if(remainTime > 3000){
            String id = payload.getId();
            redisTemplate.opsForValue().set(id,"1",remainTime, TimeUnit.MILLISECONDS);
        }
        CookieUtils.deleteCookie(
                jwtProperties.getUser().getCookieName(),
                jwtProperties.getUser().getCookieDomain(),
                response);
    }

    public String authorize(Long id, String secret) {
        ApplicationInfo info = infoMapper.selectByPrimaryKey(id);
        if(info == null){
            throw new LyException(ExceptionEnum.UNAUTHORIZED);
        }
        if(!passwordEncoder.matches(secret,info.getSecret())){
            throw new LyException(ExceptionEnum.UNAUTHORIZED);
        }
        List<Long> targetIdList = infoMapper.queryTargetIdList(id);
        AppInfo appInfo = new AppInfo();
        appInfo.setId(id);
        appInfo.setServiceName(info.getServiceName());
        appInfo.setTargetList(targetIdList);
        return JwtUtils.generateTokenExpireInMinutes(
                appInfo,jwtProperties.getPrivateKey(),jwtProperties.getApp().getExpire());
    }
}
